﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="StudyDefinitionManagementService.cs" company="ELEN 7045 GROUP II">
//   Contributed by E.Vosloo
// </copyright>
// <summary>
//   IStudyDefinitionManagementService Implementation.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Application.StudyDefinition
{
    using System;
    using System.Collections.Generic;

    using Application.Interfaces;

    using Domain.Common;
    using Domain.Setup.Entities;
    using Domain.StudyDefinition.Contracts.DomainServices;
    using Domain.StudyDefinition.Entities;

    /// <summary>
    /// IStudyDefinitionManagementService Implementation. 
    /// Serves as an orchestration layer for various study definition domain services.
    /// </summary>
    public class StudyDefinitionManagementService : IStudyDefinitionManagementService
    {
        /// <summary>
        /// The IStudyDefinitionPreparationDomainService Instance to use in this service.
        /// </summary>
        private readonly IStudyDefinitionPreparationDomainService studyDefinitionPreparationDomainServiceInstance;

        /// <summary>
        ///  The IUnitOfWork Instance to use in this service.
        /// </summary>
        private readonly IUnitOfWork unitOfWorkInstance;

        /// <summary>
        /// The IStudyTreatmentService Instance to use in this service.
        /// </summary>
        private readonly IStudyTreatmentService studyTreatmentServiceInstance;

        /// <summary>
        /// The IStudyInformationDisclosureDomainService Instance to use in this service.
        /// </summary>
        private readonly IStudyInformationDisclosureDomainService studyInformationDisclosureDomainServiceInstance;

        /// <summary>
        /// The ISubjectGroupInformationDisclosureDomainService Instance to use in this service.
        /// </summary>
        private readonly ISubjectGroupInformationDisclosureDomainService subjectGroupInformationDisclosureDomainServiceInstance;

        /// <summary>
        /// The ITreatmentInformationDisclosureDomainService Instance to use in this service.
        /// </summary>
        private readonly ITreatmentInformationDisclosureDomainService treatmentInformationDisclosureDomainServiceInstance;

        /// <summary>
        /// The IStudyMaintenanceDomainService Instance to use in this service.
        /// </summary>
        private readonly IStudyMaintenanceDomainService studyMaintenanceDomainServiceInstance;

        /// <summary>
        /// The ISubjectGroupMaintenanceDomainService Instance to use in this service.
        /// </summary>
        private readonly ISubjectGroupMaintenanceDomainService subjectGroupMaintenanceDomainServiceInstance;

        /// <summary>
        /// The ITreatmentMaintenanceDomainService Instance to use in this service.
        /// </summary>
        private readonly ITreatmentMaintenanceDomainService treatmentMaintenanceDomainServiceInstance;

        /// <summary>
        /// Initializes a new instance of the <see cref="StudyDefinitionManagementService"/> class.
        /// </summary>
        /// <param name="unitOfWork">The unit of work.</param>
        /// <param name="studyDefinitionPreparationDomainService">The study definition preparation domain service.</param>
        /// <param name="studyTreatmentService">The study treatment service.</param>
        /// <param name="studyInformationDisclosureDomainService">The study information disclosure domain service.</param>
        /// <param name="subjectGroupInformationDisclosureDomainService">The subject group information disclosure domain service.</param>
        /// <param name="treatmentInformationDisclosureDomainService">The treatment information disclosure domain service.</param>
        /// <param name="studyMaintenanceDomainService">The study maintenance domain service.</param>
        /// <param name="subjectGroupMaintenanceDomainService">The subject group maintenance domain service.</param>
        /// <param name="treatmentMaintenanceDomainService">The treatment maintenance domain service.</param>
        public StudyDefinitionManagementService(
            IUnitOfWork unitOfWork,
            IStudyDefinitionPreparationDomainService studyDefinitionPreparationDomainService, 
            IStudyTreatmentService studyTreatmentService,
            IStudyInformationDisclosureDomainService studyInformationDisclosureDomainService, 
            ISubjectGroupInformationDisclosureDomainService subjectGroupInformationDisclosureDomainService, 
            ITreatmentInformationDisclosureDomainService treatmentInformationDisclosureDomainService,
            IStudyMaintenanceDomainService studyMaintenanceDomainService,
            ISubjectGroupMaintenanceDomainService subjectGroupMaintenanceDomainService,
            ITreatmentMaintenanceDomainService treatmentMaintenanceDomainService)
        {
            if (unitOfWork == null)
            {
                throw new ArgumentNullException("unitOfWork", "The StudyDefinitionManagementService does not accept a null unitOfWork argument");
            }

            if (studyDefinitionPreparationDomainService == null)
            {
                throw new ArgumentNullException("studyDefinitionPreparationDomainService", "The StudyDefinitionManagementService does not accept a null studyDefinitionPreparationDomainService argument");
            }

            if (studyTreatmentService == null)
            {
                throw new ArgumentNullException("studyTreatmentService", "The StudyDefinitionManagementService does not accept a null studyTreatmentService argument");
            }

            if (studyInformationDisclosureDomainService == null)
            {
                throw new ArgumentNullException("studyInformationDisclosureDomainService", "The StudyDefinitionManagementService does not accept a null studyInformationDisclosureDomainService argument");
            }

            if (subjectGroupInformationDisclosureDomainService == null)
            {
                throw new ArgumentNullException("subjectGroupInformationDisclosureDomainService", "The StudyDefinitionManagementService does not accept a null subjectGroupInformationDisclosureDomainService argument");
            }

            if (treatmentInformationDisclosureDomainService == null)
            {
                throw new ArgumentNullException("treatmentInformationDisclosureDomainService", "The StudyDefinitionManagementService does not accept a null treatmentInformationDisclosureDomainService argument");
            }

            if (studyMaintenanceDomainService == null)
            {
                throw new ArgumentNullException("studyMaintenanceDomainService", "The StudyDefinitionManagementService does not accept a null studyMaintenanceDomainService argument");
            }

            if (subjectGroupMaintenanceDomainService == null)
            {
                throw new ArgumentNullException("subjectGroupMaintenanceDomainService", "The StudyDefinitionManagementService does not accept a null subjectGroupMaintenanceDomainService argument");
            }

            if (treatmentMaintenanceDomainService == null)
            {
                throw new ArgumentNullException("treatmentMaintenanceDomainService", "The StudyDefinitionManagementService does not accept a null treatmentMaintenanceDomainService argument");
            }
            
            // Assign dependencies
            this.studyDefinitionPreparationDomainServiceInstance = studyDefinitionPreparationDomainService;
            this.unitOfWorkInstance = unitOfWork;
            this.studyTreatmentServiceInstance = studyTreatmentService;
            this.studyInformationDisclosureDomainServiceInstance = studyInformationDisclosureDomainService;
            this.subjectGroupInformationDisclosureDomainServiceInstance = subjectGroupInformationDisclosureDomainService;
            this.treatmentInformationDisclosureDomainServiceInstance = treatmentInformationDisclosureDomainService;
            this.studyMaintenanceDomainServiceInstance = studyMaintenanceDomainService;
            this.subjectGroupMaintenanceDomainServiceInstance = subjectGroupMaintenanceDomainService;
            this.treatmentMaintenanceDomainServiceInstance = treatmentMaintenanceDomainService;
        }

        #region Studies

        /// <summary>
        /// Adds the specified study.
        /// </summary>
        /// <param name="study">The study to add.</param>
        /// <returns>The added study</returns>
        public Study AddStudy(Study study)
        {
            var result = this.studyDefinitionPreparationDomainServiceInstance.AddStudy(study);
            
            this.unitOfWorkInstance.Save();
            
            return result;
        }

        /// <summary>
        /// Updates the specified study.
        /// </summary>
        /// <param name="study">The study to update.</param>
        public void UpdateStudy(Study study)
        {
            this.studyMaintenanceDomainServiceInstance.UpdateStudy(study);

            this.unitOfWorkInstance.Save();
        }

        /// <summary>
        /// Deletes the specified study.
        /// </summary>
        /// <param name="study">The study to delete.</param>
        public void DeleteStudy(Study study)
        {
            this.studyMaintenanceDomainServiceInstance.DeleteStudy(study);

            this.unitOfWorkInstance.Save();
        }

        /// <summary>
        /// Gets all Studies.
        /// </summary>
        /// <returns>
        /// A list of Studies
        /// </returns>
        public List<Study> GetAllStudies()
        {
            return this.studyInformationDisclosureDomainServiceInstance.GetAllStudies();
        }

        #endregion

        #region SubjectGroups

        /// <summary>
        /// Adds the specified subjectGroup to the collection of SubjectGroups.
        /// </summary>
        /// <param name="subjectGroup">The subjectGroup to add.</param>
        /// <returns>The added subjectGroup</returns>
        public SubjectGroup AddSubjectGroup(SubjectGroup subjectGroup)
        {
            var result = this.studyDefinitionPreparationDomainServiceInstance.AddSubjectGroup(subjectGroup);
            
            this.unitOfWorkInstance.Save();

            return result;
        }

        /// <summary>
        /// Updates the specified SubjectGroup.
        /// </summary>
        /// <param name="subjectGroup">The SubjectGroup to update.</param>
        public void UpdateSubjectGroup(SubjectGroup subjectGroup)
        {
            this.subjectGroupMaintenanceDomainServiceInstance.UpdateSubjectGroup(subjectGroup);
            
            this.unitOfWorkInstance.Save();
        }

        /// <summary>
        /// Deletes the specified SubjectGroup.
        /// </summary>
        /// <param name="subjectGroup">The study to delete.</param>
        public void DeleteSubjectGroup(SubjectGroup subjectGroup)
        {
            this.subjectGroupMaintenanceDomainServiceInstance.DeleteSubjectGroup(subjectGroup);

            this.unitOfWorkInstance.Save();
        }

        /// <summary>
        /// Gets all Studies.
        /// </summary>
        /// <returns>
        /// A list of Studies
        /// </returns>
        public List<SubjectGroup> GetAllSubjectGroups()
        {
            return this.subjectGroupInformationDisclosureDomainServiceInstance.GetAllSubjectGroups();
        }

        #endregion

        #region Treatment

        /// <summary>
        /// Adds the specified treatment to the collection of Treatments.
        /// </summary>
        /// <param name="treatment">The treatment to add.</param>
        /// <returns>The added treatment</returns>
        public Treatment AddTreatment(Treatment treatment)
        {
            var result = this.studyDefinitionPreparationDomainServiceInstance.AddTreatment(treatment);
            
            this.unitOfWorkInstance.Save();

            return result;
        }

        /// <summary>
        /// Updates the specified Treatment.
        /// </summary>
        /// <param name="treatment">The Treatment to update.</param>
        public void UpdateTreatment(Treatment treatment)
        {
            this.treatmentMaintenanceDomainServiceInstance.UpdateTreatment(treatment);
            
            this.unitOfWorkInstance.Save();
        }

        /// <summary>
        /// Deletes the specified Treatment.
        /// </summary>
        /// <param name="treatment">The Treatment to delete.</param>
        public void DeleteTreatment(Treatment treatment)
        {
            this.treatmentMaintenanceDomainServiceInstance.DeleteTreatment(treatment);

            this.unitOfWorkInstance.Save();
        }

        /// <summary>
        /// Gets all Treatment.
        /// </summary>
        /// <returns>
        /// A list of Treatment
        /// </returns>
        public List<Treatment> GetAllTreatment()
        {
            return this.treatmentInformationDisclosureDomainServiceInstance.GetAllTreatment();
        }

        #endregion

        /// <summary>
        /// Adds the specified subject group to the specified study study.
        /// </summary>
        /// <param name="treatment">The treatment to assign the subject group to</param>
        /// <param name="subjectGroup">The subject group.</param>
        /// <returns>
        /// The modified Study
        /// </returns>
        public Study AddSubjectGroupToTreatment(Treatment treatment, SubjectGroup subjectGroup)
        {
            return this.subjectGroupMaintenanceDomainServiceInstance.AddSubjectGroupToTreatment(treatment, subjectGroup);
        }

        /// <summary>
        /// Removes the subject group from study.
        /// </summary>
        /// <param name="study">The study.</param>
        /// <param name="subjectGroup">The subject group.</param>
        public void RemoveSubjectGroupFromStudy(Study study, SubjectGroup subjectGroup)
        {
            this.subjectGroupMaintenanceDomainServiceInstance.RemoveSubjectGroupFromStudy(study, subjectGroup);
        }

        /// <summary>
        /// Removes the treatment from subject group.
        /// </summary>
        /// <param name="subjectGroup">The subject group.</param>
        /// <param name="treatment">The treatment.</param>
        public void RemoveSubjectGroupFromTreatment(SubjectGroup subjectGroup, Treatment treatment)
        {
            this.subjectGroupMaintenanceDomainServiceInstance.RemoveSubjectGroupFromTreatment(subjectGroup, treatment);
        }

        /// <summary>
        /// Moves the specified subject group to a new location.
        /// </summary>
        /// <param name="subjectGroup">The subject group to move.</param>
        /// <param name="location">The new location of the subject group.</param>
        /// <returns>
        /// The modified study
        /// </returns>
        public SubjectGroup MoveSubjectGroupToNewLocation(SubjectGroup subjectGroup, Location location)
        {
            return this.subjectGroupMaintenanceDomainServiceInstance.MoveSubjectGroupToNewLocation(subjectGroup, location);
        }

        /// <summary>
        /// Locks the study.
        /// </summary>
        /// <param name="study">The study.</param>
        public void LockStudy(Study study)
        {
            this.studyMaintenanceDomainServiceInstance.LockStudy(study);
            
            this.unitOfWorkInstance.Save();
        }

        /// <summary>
        /// Unlocks the study.
        /// </summary>
        /// <param name="study">The study.</param>
        public void UnlockStudy(Study study)
        {
            this.studyMaintenanceDomainServiceInstance.UnlockStudy(study);
            
            this.unitOfWorkInstance.Save();
        }

        /// <summary>
        /// Archives the specified study.
        /// </summary>
        /// <param name="study">The study to archive.</param>
        public void ArchiveStudy(Study study)
        {
            this.studyMaintenanceDomainServiceInstance.ArchiveStudy(study);
            
            this.unitOfWorkInstance.Save();
        }

        /// <summary>
        /// Gets all studies without treatments.
        /// </summary>
        /// <returns>A list of studies without treatments</returns>
        public List<Study> GetAllStudiesWithoutTreatments()
        {
            return this.studyTreatmentServiceInstance.GetAllStudiesWithoutTreatments();
        }

        /// <summary>
        /// Gets all treatments without subject groups.
        /// </summary>
        /// <returns>
        /// A list of treatments
        /// </returns>
        public List<Treatment> GetAllTreatmentsWithoutSubjectGroups()
        {
            return this.treatmentInformationDisclosureDomainServiceInstance.GetAllTreatmentsWithoutSubjectGroups();
        }
    }
}